﻿using AutoMapper;
using HuaweiCloud.Dotnet.Samples.Common;
using HuaweiCloud.Dotnet.Samples.Common.Cache.Extension;
using HuaweiCloud.Dotnet.Samples.ESports.Common;
using HuaweiCloud.Dotnet.Samples.ESports.Main.Dtos;
using HuaweiCloud.Dotnet.Samples.ESports.Main.Entities;
using HuaweiCloud.Dotnet.Samples.ESports.Main.Service;
using HuaweiCloud.Dotnet.Samples.ESports.Main.Specification;
using Medallion.Threading;
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.Guids;

namespace HuaweiCloud.Dotnet.Samples.ESports.Main.Manager
{
    public class EventsManager : IEventsManager
    {
        private readonly IRepository<CompletedEvents> _ceRepository;
        private readonly ICommunityEventsService _eventsServices;
        private readonly IDistributedCache _cache;
        private readonly IGuidGenerator _idGenerator;
        private readonly IDistributedLockProvider _lockProvider;
        private readonly IMapper _mapper;
        private static string _key = RedisConst.RunningEvents;
        private static string _locker = $"locker-{ _key }";
        public EventsManager(IRepository<CompletedEvents> ceRepository
            , ICommunityEventsService eventsServices
            , IDistributedCache cache
            , IGuidGenerator idGenerator
            , IDistributedLockProvider lockProvider
            , IMapper mapper)
        {
            _ceRepository = ceRepository;
            _eventsServices = eventsServices;
            _cache = cache;
            _idGenerator = idGenerator;
            _lockProvider = lockProvider;
            _mapper = mapper;
        }

        public async Task<bool> CheckEventsCompletedAsync(Guid userId, Guid eventsId, CancellationToken token = default)
        {
            var item = await _ceRepository.FirstOrDefaultAsync(new CompletedEventsSpecification(userId, eventsId), token);
            return item != null;
        }

        public bool CheckSportEvents(CommunityEventsDto misson, string type, int distance)
        {
            var isCompleted = false;
            if (misson.EventConditions == null)
                return false;
            foreach (var c in misson.EventConditions)
            {
                if (c.Key == type && distance >= c.Value)
                    isCompleted = true;
            }
            return isCompleted;
        }

        public bool CheckStepEvents(CommunityEventsDto misson, int steps)
        {
            var isCompleted = false;
            if (misson.EventConditions == null)
                return false;
            foreach (var c in misson.EventConditions)
            {
                if (c.Key == EventsConditionConst.Step && steps >= c.Value)
                    isCompleted = true;
            }
            return isCompleted;
        }

        public async Task CompletedEventsAsync(Guid userId, Guid eventsId, CancellationToken token = default)
        {
            await _ceRepository.AddAsync(
                new CompletedEvents(_idGenerator.Create(), userId, eventsId)
            );
        }

        public async Task<List<CommunityEventsDto>?> GetRunningAsync(CancellationToken token = default)
        {
            var defaultFactory = async () => {
                var temp = await _eventsServices.ListAsync(new CommunityEventsSpecification(DateTime.Now), token);
                if(temp.Count == 0)
                {
                    var events = InitDailyEvents();
                    await using (var locker = await _lockProvider.TryAcquireLockAsync(_locker, TimeSpan.FromSeconds(5)))
                    {
                        if (locker != null)
                            foreach (var e in events)
                                await _eventsServices.AddAsync(e, token);
                        else
                            throw new Exception("Trying");
                    }
                    temp = _mapper.Map<List<CommunityEventsDto>>(events);
                }
                return temp;
            };
            var expired = DateTime.Today;
            // 活动缓存过期时间为次日凌晨0点
            expired = expired.AddDays(1);
            var optionFactory = () => new DistributedCacheEntryOptions()
            {
                AbsoluteExpiration = new DateTimeOffset(expired)
            };
            return await _cache.GetOrDefaultAsync(_key, defaultFactory, optionFactory);

        }
        /// <summary>
        /// 初始化日常任务
        /// </summary>
        /// <returns></returns>
        private List<CreateCommunityEventsDto> InitDailyEvents()
        {
            var res = new List<CreateCommunityEventsDto>();
            // 日常步数任务
            var dailyStep = new CreateCommunityEventsDto()
            {
                Id = _idGenerator.Create(),
                StartTime = DateTime.Today,
                EndTime = DateTime.Today.AddDays(1),
                Description = "Daily 10000",
                Points = 10,
                EventConditions = new List<EventConditionDto>() { 
                    new EventConditionDto(EventsConditionConst.Step, 10000) 
                }
            };
            res.Add(dailyStep);

            var types = SportTypeConsts.Types;
            foreach(var t in types)
            {
                dailyStep = new CreateCommunityEventsDto()
                {
                    Id = _idGenerator.Create(),
                    StartTime = DateTime.Today,
                    EndTime = DateTime.Today.AddDays(1),
                    Description = $"Daily { t } 5000",
                    Points = 10,
                    EventConditions = new List<EventConditionDto>() {
                        new EventConditionDto(t, 5000)
                    }
                };
                res.Add(dailyStep);
            }
            return res;
        }
    }
}
